package com.hfzy.ihk.web.freeswitchCall.biz;

import com.alibaba.fastjson.JSON;
import com.hfzy.ihk.common.eventSocket.enums.EventName;
import com.hfzy.ihk.common.util.date.DateUtils;
import com.hfzy.ihk.common.util.string.StringTools;
import com.hfzy.ihk.common.util.string.StringUtil;
import com.hfzy.ihk.common.util.uuid.base64uuid.UUIDs;
import com.hfzy.ihk.facade.aliyuncall.enums.MsgTypeEnum;
import com.hfzy.ihk.facade.freeswitchCall.enums.CallTypeEnum;
import com.hfzy.ihk.facade.freeswitchCall.vo.FreeswitchCallState;
import com.hfzy.ihk.web.freeswitchCall.constant.*;
import com.hfzy.ihk.web.freeswitchCall.context.DisruptorInitBean;
import com.hfzy.ihk.web.freeswitchCall.context.EventSocketInitBean;
import com.hfzy.ihk.web.freeswitchCall.support.SampleMemoryCache;
import com.hfzy.ihk.web.freeswitchCall.support.disruptor.DisruptorSupport;
import com.hfzy.ihk.web.freeswitchCall.support.freeswitch.event.FreeswitchCallStateEvent;
import com.hfzy.ihk.web.freeswitchCall.vo.VoiceRTASRReportVo;
import com.lmax.disruptor.RingBuffer;
import org.freeswitch.esl.client.transport.event.EslEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: Administrator
 * @Date: 2018/10/31 09:19
 * @Description:
 */
@Lazy
@Component
public class FreeswitchCallStateBiz extends DisruptorSupport<FreeswitchCallState, FreeswitchCallStateEvent> implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(FreeswitchCallStateBiz.class);

    @Autowired
    EventSocketInitBean eventSocketInitBean;

    @Autowired
    PushDataToAnalysis pushDataToAnalysis;

    @Autowired
    PushDataToBrowserBiz pushDataToBrowserBiz;

    @Autowired
    private RedisTemplate redisTemplate;

    HashOperations hashOperations;

    //对外访问的url
    @Value("${freeswitch.web.recordFileUrl}")
    private String  recordFileUrl;

    @Value("${freeswitch.web.url}")
    private String serverUrl;

    @Override
    public void afterPropertiesSet() throws Exception {
        hashOperations = redisTemplate.opsForHash();
    }

    @Override
    protected RingBuffer<FreeswitchCallStateEvent> useRingBuffer(FreeswitchCallState data) {

        int index = 0;
        RingBuffer ringBuffer = null;

        String useType = "Freeswitch中间状态";

        String sessionId = data.getEvent().getEventHeaders().get("Channel-Call-UUID");

        if(StringTools.isEmpty(sessionId)){
            sessionId = data.getEvent().getEventHeaders().get("sessionId");
        }

        if (StringTools.isEmpty(sessionId))
            return null;

        //session 做hash 判断应该进哪一个队列
        index = sessionId.hashCode() % PublicConfig.ALIYUN_CALL_STATE_BUFFER_NUM_SIZE;

        ringBuffer = DisruptorInitBean.getRingBufferFreeswitchCallState(Math.abs(index));

        checkRingBufferUse(ringBuffer, useType);
        return ringBuffer;

    }


    /**
     * 处理状态消息
     *
     * @param
     */

    public void dealCallState(EslEvent event) {
/*        //TODO
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/

        FreeswitchCallState freeswitchCallState=initFreeswitch(event);

        if (StringTools.isEmpty(freeswitchCallState)) {
            return;
        }

        putInRingBuffer(freeswitchCallState);

    }

    /**
     * 初始化freeswitchState
     * @param event
     * @return
     */
    public FreeswitchCallState initFreeswitch(EslEvent event) {

        FreeswitchCallState callState=new FreeswitchCallState(event);

        if (StringUtil.isNotNull(event)) {
            //取得freeswitch所有头信息
            Map<String, String> eventHeaders = event.getEventHeaders();
            //获取sessionId,事件名,当前号码
            String sessionId = eventHeaders.get("Channel-Call-UUID");
            /**自定义的消息中sessionId的值就是sessionId字段，而没有Channel-Call-UUID*/
            if(StringTools.isEmpty(sessionId)){
                sessionId = eventHeaders.get("sessionId");
            }
            if(StringTools.isEmpty(sessionId)){
                logger.error("initFreeswitch failed! sessionId读取失败！");
            }

            String eventName = eventHeaders.get("Event-Name");

            //redisKey
            String redisKey = RedisKey.CALL_HISTORY_RPIX + sessionId;
            //TODO
            //从redis获取主叫号码和被叫号码
            String mainCallPhone = (String) hashOperations.get(redisKey, RedisFields.CALL_HISTORY_MAIN_CALL_PHONE);

            String sipUser = (String)hashOperations.get(redisKey, RedisFields.FS_SIP_USER);
            String targetCallPhone = (String) hashOperations.get(redisKey, RedisFields.CALL_HISTORY_TARGET_CALL_PHONE);

            //开始进行freeswitch状态设置
            callState.setOut_id(sessionId);
            String destinationNumber=eventHeaders.get("Caller-Destination-Number");
            String sipToUser = eventHeaders.get("variable_sip_to_user");
            String channelName = eventHeaders.get("Channel-Name");
            callState.setDestinationNumber(destinationNumber);
            callState.setChannelName(channelName);
            callState.setStatus_code(eventName);
            callState.setCaller("null".equals(sipUser)?mainCallPhone:sipUser); //这里涉及选线和没有选线的控制
            callState.setCallee(targetCallPhone);
            callState.setStatus_time(event.getEventDateLocal());
            callState.setSessionId(sessionId);
            callState.setCall_id(eventHeaders.get("Core-UUID"));
            callState.setSipToUser(sipToUser);
            //先设置为中间状态
            callState.setMsgType(AliyunAkInfo.VOICECALLREPORT);


            switch (EventName.fromName(eventName)){

                case CHANNEL_HANGUP_COMPLETE:

                    //为了避免话单重复记录,因此只将第一个CHANNEL_HANGUP_COMPLETE作为话单状态返回
                    if ((destinationNumber.contains(targetCallPhone)||destinationNumber.contains(sipUser))&&(!redisTemplate.hasKey(RedisKey.CALL_HISTORY_RPIX + sessionId+"_CDR"))){

                        redisTemplate.opsForValue().set(RedisKey.CALL_HISTORY_RPIX + sessionId+"_CDR","true",1, TimeUnit.DAYS);

                        //设置为话单返回状态
                        callState.setMsgType(AliyunAkInfo.VOICEREPORT);

                        //当前event返回的时间
                        String endTimeString = DateUtils.stringFromString(event.getEventDateLocal(), DateUtils.DATE_FORMAT_DATETIME_SSS);

                        //转化为long类型,待会要计算通话时长
                        long endTime = DateUtils.getDateFromString(endTimeString,DateUtils.DATE_FORMAT_DATETIME_SSS).getTime();

                        //取出主叫和被叫应答时间
                        String targetStartTimeString = (String) hashOperations.get(redisKey, RedisFields.CALL_HISTORY_TARGET_CALL_ANSWERED_TIME);
                        String mainStartTimeString = (String)hashOperations.get(redisKey, RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED_TIME);

                        if (targetStartTimeString!=null){//假如被叫有应答,计算被叫通话时长,设置相关参数

                            //转化为long类型,要计算通话时长
                            long targetStartTime = DateUtils.getDateFromString(targetStartTimeString, "yyyyMMddHHmmssSSS").getTime();

                            callState.setDuration(String.valueOf(( endTime- targetStartTime)/1000));
                            callState.setStart_time(targetStartTimeString);
                            callState.setEnd_time(endTimeString);

                        }

                        if (mainStartTimeString!=null){//假如主叫有应答,计算主叫通话时长,设置相关参数
                            //转化为long类型,要计算通话时长
                            long mainStartTime = DateUtils.getDateFromString(mainStartTimeString, "yyyyMMddHHmmssSSS").getTime();
                            callState.setA_duration(String.valueOf((endTime-mainStartTime)/1000));
                            callState.setA_start_time(mainStartTimeString);
                            callState.setA_end_time(endTimeString);
                        }

                    }

                    //}
                break;
/*                case RECORD_STOP: //录音结束
                    String recordFilePath =(String)hashOperations.get(RedisKey.CALL_HISTORY_RPIX + sessionId + "_temp", "recordFilePath");

                    if(StringUtil.isNotNull(recordFilePath)){
                        callState.setRecordFileUrl(serverUrl+recordFileUrl+recordFilePath);
                        logger.info("freeswitch录音文件url:"+serverUrl+recordFileUrl+recordFilePath);
                    }
                    break;*/
            }
        }

        return callState;
    }

    /**-------------------------------自定义消息处理--------------------------------*/

    /**
     * 处理语音识别
     */
    public void handleAlibabaAsr(EslEvent event){

        Map<String, String> eventHeaders = event.getEventHeaders();

        String sessionId = eventHeaders.get("session_id");

        VoiceRTASRReportVo voiceRTASRReportVo = getVoiceRTASRReportVo(eventHeaders);

        logger.info("收到freeswitch语音分析结果:sessionId:"+sessionId);

        if(StringTools.isEmpty(sessionId)) {
            logger.info("----->消息队列接收ars消息，获取sessionId异常："+JSON.toJSONString(event));
            return ;
        }
        String[] arg = pushDataToAnalysis.readPackageIdAndCallTaskId(sessionId);

        if(arg==null||arg.length<2){

            logger.info("-------------->packageId和callTaskId为null或者只有一个,不继续处理,sessionId:"+sessionId);

            return ;
        }
        logger.info("-------------->获得arg length:"+arg.length);
        //填写推送代码 获取callTaskId 和 packageId
        logger.info("---->packageId:{},callTaskId:{},",arg[0],arg[1]);
        //根据sessionId推送到客户端
        Long start =System.currentTimeMillis();
        try {
            pushDataToBrowserBiz.pushAsrToBrowser(voiceRTASRReportVo, CallTypeEnum.FREESWITCH_CALL.getValue()); //异步
        }catch (Exception e){
            logger.error("--------->推送识别结果到浏览器异常，sessionId:{}",voiceRTASRReportVo.getOut_id(),e);
        }
        logger.info("pushAsrToBrowser将words推送浏览器 入队时间："+(System.currentTimeMillis()-start));

        //进推送队列推送
        Long start1 =System.currentTimeMillis();
        try {
            pushDataToAnalysis.pushData(arg[0], arg[1], voiceRTASRReportVo.getOut_id(),  voiceRTASRReportVo, CallTypeEnum.FREESWITCH_CALL.getValue(), MsgTypeEnum.NORMAL.getValue()); //异步
        }catch (Exception e){
            logger.error("--------->推送识别结果到分析服务器异常，sessionId:{}",voiceRTASRReportVo.getOut_id(),e);
        }
        logger.info("将words推送分析服务器入队时间："+(System.currentTimeMillis()-start1));
    }


    /**
     * 网关注册：
     * {"eventBodyLines":[],"eventDateGmt":"Wed, 03 Apr 2019 02:48:55 GMT","eventDateLocal":"2019-04-03 10:48:55",
     * "eventDateTimestamp":1554259735657318,"eventHeaders":{"profile-name":"internal","":"","from-user":"19900000004",
     "expires":"1800","Core-UUID":"3bf4185b-aa40-4bc9-b425-17e7ee6c84bf","outbound_caller_id_name":"FreeSWITCH","user_name":"19900000004",
     "effective_caller_id_number":"19900000004","FreeSWITCH-Switchname":"FS_SRV_8209.localdomain","Event-Calling-Line-Number":"2006",
     "FreeSWITCH-Hostname":"FS_SRV_8209.localdomain","sip_auth_realm":"172.16.200.60","presence-hosts":"172.16.200.60,172.16.200.60",
     "number_alias":"19900000004","Event-Date-Local":"2019-04-03 10:48:55","effective_caller_id_name":"Extension 19900000004","
     domain_name":"172.16.200.60","outbound_caller_id_number":"0000000000","FreeSWITCH-IPv6":"::1","directory-exten-visible":"true",
     "network-port":"5064","FreeSWITCH-IPv4":"172.16.200.60","contact":"\"\" <sip:19900000004@172.16.200.81:5064>",
     "call-id":"2419aace2befd1496605ef6e0dc40804@172.16.200.60",
     "network-ip":"172.16.200.81","Event-Date-GMT":"Wed, 03 Apr 2019 02:48:55 GMT","to-host":"172.16.200.60
     ","sip_number_alias":"19900000004","user_context":"default","limit_max":"15","Event-Date-Timestamp":"1554259735657318",
     "from-host":"172.16.200.60","sip_auth_username":"19900000004","rpid":"unknown","Event-Calling-Function":"sofia_reg_handle_register_token"
     ,"to-user":"19900000004","Event-Name":"CUSTOM","Event-Sequence":"458715","callgroup":"techsupport",
     "Event-Subclass":"sofia::register","Event-Calling-File":"sofia_reg.c","realm":"172.16.200.60","toll_allow":"domestic,
     international,local","accountcode":"19900000004","directory-visible":"true","status":"Registered(UDP)",
     "username":"19900000004","user-agent":"SWX32BU"},"eventName":"CUSTOM","messageHeaders":{"CONTENT_LENGTH":"1490","CONTENT_TYPE":"text/event-plain"}}

     * 用户注册,取消注册
     * @param event
     */
    public void userInfo(EslEvent event) {

        Map<String, String> eventHeaders = event.getEventHeaders();

        String subclass = eventHeaders.get("Event-Subclass");

        //"" <sip:19900000004@172.16.200.81:5064>
        String contact = eventHeaders.get("contact");

        //sip.js发送的取消注册信息居然没有contact头...
        if (!StringUtil.isNotNull(contact)){
            String user = eventHeaders.get("from-user");
            logger.info("freeswitchLog: 有可能是前台网页的用户取消注册,没有contact头,user为:"+(user==null?"未知":user) );
            return;
        }
        if (subclass.equals("sofia::unregister")) {

            if (contact.contains("sip:199000")) {

                logger.info("freeswitchLog: 有网关取消注册,contact:" + contact);

            } else {

                logger.info("freeswitchLog: 有用户取消注册,contact:" + contact);
            }


        } else {

            if (contact.contains("sip:199000")) {
                //TODO
                String sipUser = eventHeaders.get("username");
                String ip = eventHeaders.get("network-ip");
                String port = eventHeaders.get("network-port");

                SampleMemoryCache.gatewayContrcatInfo.put(sipUser,StringUtil.strConnect("@",ip,":",port));

                logger.info("新的网关注册,总数：{},sipUser:{},ip:{},port:{}。current contractStr：{}",
                        SampleMemoryCache.gatewayContrcatInfo.size(),sipUser,ip,port,SampleMemoryCache.gatewayContrcatInfo.get(sipUser));

            } else {
                //"pro138000000005" <sip:13800000005@10.10.37.178:50859;ob>
                //"" <sip:1069@s8giq2e72paq.invalid;transport=ws;fs_nat=yes;fs_path=sip:1069@218.30.128.98:44993;transport=ws>
                logger.info("freeswitchLog: 有新的用户注册,contact:" + contact);

            }

        }

    }


    /**
     * 发现是网关未注册的时候，将从选线出来的idle重新放回redis 避免丢失,
     * 好像暂时实现不了，不知道城市，所以无法知道应该放入哪一个队列
     */
    public void putIdleWhenGatewayNoRegistered(String gatewayChannelIndex ,String gatewaySipUser){
        //将卡槽放回redis
        if(gatewayChannelIndex==null||gatewaySipUser==null)
            return;
        gatewayChannelIndex = "swx"+Integer.valueOf(gatewayChannelIndex).toString();

        gatewaySipUser = "199000000"+gatewaySipUser;


    }


    public void handleLineBusy(EslEvent event) {

        FreeswitchCallState freeswitchCallState=initFreeswitch(event);

        if (StringTools.isEmpty(freeswitchCallState)) {
            return;
        }
        logger.debug("putInRingBuffer:{}",JSON.toJSONString(freeswitchCallState));

        putInRingBuffer(freeswitchCallState);
    }

    /**
     * 封装语音识别vo
     */
    public VoiceRTASRReportVo getVoiceRTASRReportVo(Map<String,String> params){

        VoiceRTASRReportVo voiceRTASRReportVo=new VoiceRTASRReportVo();
        voiceRTASRReportVo.setRole(params.get("role"));
        //voiceRTASRReportVo.setIdentity();
        voiceRTASRReportVo.setWordId(UUIDs.randomBase64UUID());
        voiceRTASRReportVo.setBegin_offset("0");
        voiceRTASRReportVo.setEnd_offset("0");
        //voiceRTASRReportVo.setBegin_time();
        //voiceRTASRReportVo.setCall_id();
        voiceRTASRReportVo.setOut_id(params.get("session_id"));
        Map<String,Map<String,Object>> asrResponse = JSON.parseObject(params.get("asr_response"), Map.class);
        voiceRTASRReportVo.setWords((String)(asrResponse.get("payload").get("result")));

        return voiceRTASRReportVo;
    }

    /**
     * 语音识别结束通知语音分析服务器
     * @param event
     */
    public void handleSpeechRecognitionEnd(EslEvent event){

        Map<String, String> eventHeaders = event.getEventHeaders();
        String sessionId = eventHeaders.get("session_id");

        redisTemplate.setEnableTransactionSupport(true);
        redisTemplate.multi();
        redisTemplate.opsForValue().setIfAbsent(RedisKey.IDENTIFICATION_END_STATE+sessionId,"true");
        redisTemplate.expire(RedisKey.IDENTIFICATION_END_STATE+sessionId, RedisTimeOut.CACHE_THREE_DAY, TimeUnit.SECONDS);
        List result = redisTemplate.exec(); // 这里result会返回事务内每一个操作的结果，如果setIfAbsent操作失败后，result[0]会为false。
        if(Boolean.valueOf(result.get(0).toString())){
            String[] packageIdAndCallTaskId = pushDataToAnalysis.readPackageIdAndCallTaskId(sessionId);
            if(packageIdAndCallTaskId!=null&&packageIdAndCallTaskId.length>1) {
                logger.info("----->发送freeswitch通话结束标识到分析服务器sessionId:{}",sessionId);
                try {
                    pushDataToAnalysis.pushData(packageIdAndCallTaskId[0], packageIdAndCallTaskId[1], sessionId,  new VoiceRTASRReportVo(), CallTypeEnum.FREESWITCH_CALL.getValue(), MsgTypeEnum.END.getValue());
                }catch (Exception e){
                    logger.error("--------->发送freeswitch通话结束状态到分析服务器异常，sessionId:{}",sessionId,e);
                }
            }
        }
    }
}